//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<RenderManager.cpp>
///	@path	~/src/graphics/
///	@date	2007/11/15
///	@desc	Render integration.

#include "config/config.h"

#include "lib/system/thread_debug.h"

#include "graphics/IRenderer.h"
#include "graphics/RenderManager.h"
#include "graphics/batch/CMainBatch.h"
#include "graphics/canvas/CCanvasSlot.h"
#include "graphics/dx9/CRenderer9.h"
#include "graphics/dx10/CRenderer10.h"

namespace xeres {

	// RenderManager
	RenderManager::RenderManager( void )
	{

	}
	// ~RenderManager
	RenderManager::~RenderManager( void )
	{

	}
	// Initialize
	void RenderManager::Initialize( void )
	{
		// register default effect loader
		RegisterShaderLoader( _S("RenderManager::DefaultShaderLoader") , &DefaultShaderLoader );

		RenderPipeline::Initialize();

		// Create a default shading pass as main pass.
 		Ref<IPass> mainPass = GetRenderer()->DefaultShadingPass();
 		SetMainPass( mainPass );
	}
	// Finalize
	void RenderManager::Finalize( void )
	{
		RenderPipeline::Finalize();
		m_effectLoaders.clear();
		m_shaderLoaders.clear();
		m_loadedEffects.clear();
		m_loadedShaders.clear();
	}

	// Render
	void RenderManager::Render( void )
	{
		TRACK_FUNCTION_SCOPE();
		RUNNING_ON_THREAD( _S("render") );

		RenderPipeline::Render();
	}

	// ChangeShadingMode
	void RenderManager::ChangeShadingMode( const WString& mode )
	{

	}
	// SetOverlaySlot
	void RenderManager::SetOverlaySlot( size_t count )
	{
		SetOverlay( new CCanvasSlot( count ) );
	}
	// SetOverlayCanvas
	void RenderManager::SetOverlayCanvas( size_t slot , RefWeak<ICanvas> canvas )
	{
		RefWeak<CCanvasSlot> c = GetOverlay();
		c->SetSlot( slot , canvas );
	}
	// RegisterEffectLoader
	void RenderManager::RegisterEffectLoader( const WString& name , EffectLoader loader )
	{
		for( size_t i = 0 , total = m_effectLoaders.size() ; i < total ; ++i )
		{
			if( m_effectLoaders[i].first == name )
			{
				TRACE_ERROR( _S("RenderManager::RegisterEffectLoader: Effect loader '%s' exists.") , name.c_str() );
				return;
			}
		}
		m_effectLoaders.push_back( std::make_pair( name , loader ) );
	}
	// DeregisterEffectLoader
	void RenderManager::DeregisterEffectLoader( const WString& name )
	{
		for( size_t i = 0 , total = m_effectLoaders.size() ; i < total ; ++i )
		{
			if( m_effectLoaders[i].first == name )
			{
				m_effectLoaders.erase( m_effectLoaders.begin() + i );
				return;
			}
		}
		TRACE_ERROR( _S("RenderManager::DeregisterEffectLoader: Effect loader '%s' not found.") , name.c_str() );
	}
	// RegisterShaderLoader
	void RenderManager::RegisterShaderLoader( const WString& name , ShaderLoader loader )
	{
		for( size_t i = 0 , total = m_shaderLoaders.size() ; i < total ; ++i )
		{
			if( m_shaderLoaders[i].first == name )
			{
				TRACE_ERROR( _S("RenderManager::RegisterShaderLoader: Shader loader '%s' exists.") , name.c_str() );
				return;
			}
		}
		m_shaderLoaders.push_back( std::make_pair( name , loader ) );
	}
	// DeregisterShaderLoader
	void RenderManager::DeregisterShaderLoader( const WString& name )
	{
		for( size_t i = 0 , total = m_shaderLoaders.size() ; i < total ; ++i )
		{
			if( m_shaderLoaders[i].first == name )
			{
				m_shaderLoaders.erase( m_shaderLoaders.begin() + i );
				return;
			}
		}
		TRACE_ERROR( _S("RenderManager::DeregisterShaderLoader: Shader loader '%s' not found.") , name.c_str() );
	}
	// QueryEffect
	RefWeak<IEffect> RenderManager::QueryEffect( const WString& url )
	{
		// strip slash
		WString str(url);
		normalize_slash( str.begin() , str.end() , '/' );

		// check if effect cached
		dict< WString,Ref<IEffect> >::iterator it = m_loadedEffects.find( str );
		if( it != m_loadedEffects.end() )
		{
			return it->second;
		}
		return NULL;
	}
	// QueryShader
	RefWeak<IShader> RenderManager::QueryShader( const WString& url )
	{
		// strip slash
		WString str(url);
		normalize_slash( str.begin() , str.end() , '/' );

		// check if effect cached
		dict< WString,Ref<IShader> >::iterator it = m_loadedShaders.find( str );
		if( it != m_loadedShaders.end() )
		{
			return it->second;
		}
		return NULL;
	}
	// LoadEffect
	RefPass<IEffect> RenderManager::LoadEffect( const WString& url , RefWeak<IEffectPool> pool , bool cache )
	{
		// strip slash
		WString str(url);
		normalize_slash( str.begin() , str.end() , '/' );

		// check if effect cached
		dict< WString,Ref<IEffect> >::iterator it = m_loadedEffects.find( str );
		if( it != m_loadedEffects.end() )
		{
			return RefPass<IEffect>( it->second );
		}

		Ref<IEffect> retval;
		for( size_t i = 0 , total = m_effectLoaders.size() ; i < total ; ++i )
		{
			retval = m_effectLoaders[i].second( str , pool , *this );
			if( retval.IsValid() )
			{
				if( cache )
					m_loadedEffects[ str ] = retval;
				return RefPass<IEffect>( retval );
			}
		}
		return NULL;
	}
	// LoadShader
	RefPass<IShader> RenderManager::LoadShader( const WString& url , bool cache )
	{
		// strip slash
		WString str(url);
		normalize_slash( str.begin() , str.end() , '/' );

		// check if effect cached
		dict< WString,Ref<IShader> >::iterator it = m_loadedShaders.find( str );
		if( it != m_loadedShaders.end() )
		{
			return RefPass<IShader>( it->second );
		}

		Ref<IShader> retval;
		for( size_t i = 0 , total = m_shaderLoaders.size() ; i < total ; ++i )
		{
			retval = m_shaderLoaders[i].second( str , *this );
			if( retval.IsValid() )
			{
				if( cache )
					m_loadedShaders[ str ] = retval;
				return RefPass<IShader>( retval );
			}
		}
		return NULL;
	}
	// DefaultShaderLoader
	RefPass<IShader> RenderManager::DefaultShaderLoader( const WString& url , RenderManager& rm )
	{
		// take effect from url
		size_t pos = url.find_last_of( ':' );
		if( pos == WString::npos )
		{
			TRACE_DEBUG( _S("RenderManager::DefaultLoadShader: URL has no shader of effect declaration." ) );
			return NULL;
		}
		WString effect_url( url.substr( 0 , pos ) );
		WString wshader_name( url.substr( pos + 1 ) );
		AString shader_name;
		wcs_to_mbs( wshader_name , shader_name );

		RefWeak<IEffect> effect = rm.QueryEffect( effect_url );
		if( effect.IsNull() )
			return NULL;

		Ref<IShader> loaded = effect->GetTechnique( shader_name );
		return loaded;
	}

} // namespace xeres
